package com.company.cloud.common.redis;

import java.util.List;
import java.util.NoSuchElementException;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StreamOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;

@Configuration
public class RedisAutoConfigure {

	@Autowired
	private RedisConnectionFactory factory;

	@Autowired
	private RedisProperties redisProperties;

	@Bean
	public RedissonClient redissonClient() {
		Config config = new Config();
		if (redisProperties.getSentinel() == null) {
			config.useSingleServer()
					.setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort());
			config.useSingleServer().setDatabase(redisProperties.getDatabase())
					.setPassword(redisProperties.getPassword()).setIdleConnectionTimeout(1000).setConnectTimeout(30000);
			if (StringUtils.isEmpty(redisProperties.getPassword())) {
				config.useSingleServer().setPassword(null);
			}
		} else {
			SentinelServersConfig sentinelServersConfig = null;
			List<String> redisNodes = redisProperties.getSentinel().getNodes();
			for (String redisNode : redisNodes) {
				sentinelServersConfig = config.useSentinelServers().addSentinelAddress("redis://" + redisNode);
			}
			if (sentinelServersConfig != null) {
				sentinelServersConfig.setDatabase(redisProperties.getDatabase())
						.setMasterName(redisProperties.getSentinel().getMaster())
						.setPassword(redisProperties.getPassword()).setMasterConnectionPoolSize(500)
						.setSlaveConnectionPoolSize(500).setIdleConnectionTimeout(1000).setConnectTimeout(30000);
				if (StringUtils.isEmpty(redisProperties.getPassword())) {
					sentinelServersConfig.setPassword(null);
				}
			}
		}
		return Redisson.create(config);
	}
	
	
//	@Bean(name = "wjjRedis")
//	public RedisTemplate<String, Object>  wjjRedis() {
//		String hostName="127.0.0.1";
//		int port=6379;
//		int dataBaseIndex=10;
//		String password="";
//		
//		RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
//		configuration.setHostName(hostName);
//		configuration.setPort(port);
//		configuration.setDatabase(dataBaseIndex);
//        if (!StringUtils.isEmpty(password)) {
//            RedisPassword redisPassword = RedisPassword.of(password);
//            configuration.setPassword(redisPassword);
//        }
//        
//        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
//        genericObjectPoolConfig.setMaxIdle(10);
//        genericObjectPoolConfig.setMaxTotal(1000);
//        genericObjectPoolConfig.setMinIdle(5);
//        genericObjectPoolConfig.setMaxWaitMillis(-1);
//        
//        LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder =
//        		LettucePoolingClientConfiguration.builder();
//        LettuceClientConfiguration clientConfiguration = builder.poolConfig(genericObjectPoolConfig).build();
//        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(configuration, clientConfiguration);
//        lettuceConnectionFactory.afterPropertiesSet();
//        
//    	RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//		redisTemplate.setKeySerializer(new StringRedisSerializer());
//		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//		redisTemplate.setHashValueSerializer(new StringRedisSerializer());
//		redisTemplate.setValueSerializer(new StringRedisSerializer());
//		redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//		
//		return redisTemplate;
//	}


	@Bean
	public RedisTemplate<String, Object> redisTemplate() {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new StringRedisSerializer());
//	    redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
		redisTemplate.setConnectionFactory(factory);
		return redisTemplate;
	}

	@Bean
	public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForHash();
	}

	@Bean
	public StreamOperations<String, String, String> streamOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForStream();
	}

	@Bean
	public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
		return redisTemplate.opsForValue();
	}

	@Bean
	public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForList();
	}

	@Bean
	public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForSet();
	}

	@Bean
	public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForZSet();
	}

}
